﻿#Область ОбластьПараметров
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2019, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////


// Параметры процедуры обновления
var now = new Date()
var outFileName = 'log' + now.valueOf() + '.txt' // Путь к log-файлу
var cfgFileNames = [ИменаФайловОбновления] // Пути к .cf/.cfu-файлам с обновлениями
var fixFileNames = [ИменаФайловИсправлений] // Пути к .cfe файлам с исправлениями
var removeFixNames = [ИменаУдаляемыхИсправлений] // Имена исправлений, которые необходимо удалить
var v8conf = [ИмяИсполняемогоФайлаКонфигуратора] // Путь к исполняемому файлу 1С:Предприятия 8
var v8client = [ИмяИсполняемогоФайлаКлиента] // Путь к исполняемому файлу 1С:Предприятия 8
var v8comcntr = [ПутьКCOMСоединителю] // Путь к comcntr.dll
var v8logEncoding = '[КодировкаЛогФайла]'

var infoBasePath = [ПараметрПутиКИнформационнойБазе]
var BaseFileName = [СтрокаПутиКФайлуИнформационнойБазы]
var unlockCode = '[КодРазблокировки]'
var connectionString = [СтрокаСоединенияИнформационнойБазы] + ';UC=[КодРазблокировки]'

var backupFileName = [КаталогРезервнойКопии] + '1Cv8' + now.valueOf() + '.1CD' // Файл резервной копии
var UseRestore = [ВосстанавливатьИнформационнуюБазу] // Использовать восстановление ИБ в случае падения
var createBackup = [СоздаватьРезервнуюКопию] // создавать резервную копию

var eventLogID = [СобытиеЖурналаРегистрации]
var emailAddress = [АдресЭлектроннойПочты] // адрес электронной почты для отправки уведомления
var adminName = [ИмяАдминистратораОбновления] // имя администратора, инициировавшего обновление

var doBlockUsers = [БлокироватьСоединенияИБ] // устанавливать блокировку соединений перед обновлением
var comConnectorName = [ИмяCOMСоединителя] // имя COM-класса для работы с 1С:Предприятием 8 через COM-соединение
var useComConnector = [ИспользоватьCOMСоединитель] // флаг использования COM-соединения для работы с 1С:Предприятием 8

var startEnterprise = [ЗапускСеансаПослеОбновления] // выполнять запуск предприятия после обновления
var makeCompression = [ВыполнятьСжатиеТаблицИБ] // запускать сжатие таблиц информационной базы
var executeDeferredHandlers = [ВыполнитьОтложенныеОбработчики] // выполнить отложенные обработчики обновления

var tempLogFileName = 'templog.txt' // временный лог-файл платформы с параметром /out 
var errorFileName = 'error.txt' // имя файла-маркера ошибок для параметров /C ВыполнитьОбновлениеИЗавершитьРаботу и ВыполнитьЗагрузкуРасширенийИЗавершитьРаботу

var taskNameScheduleService = [ИмяЗадачиПланировщикаЗадач] // Если указано, то задача, которой запущен скрипт.
var runAppAdditionalParams = [ПараметрыЗапускаПредприятия] // Аргументы командной строки, которые следует добавить к запуску 1С:Предприятия в режиме клиента.
var updateConfiguration = [ВыполнитьОбновлениеКонфигурации]
var loadExtentions = [ВыполнитьЗагрузкуРасширений]

#КонецОбласти

#Область ОбластьОбновленияКонфигурации

var thisFileName
var thisFileDir
var InfoBasePassword
var ClusterPassword

// Переменные состояния
var backupCreated = false
var connectionsDenied = false

// Глобальная переменная com-соединения
var ComConnection = null

// Переменные состояния функции doDisconnectAndBlockUsersHTA()
var disconnectionStep = 0
var disconnectionInterval
var disconnectionStartDateTime

// Открыть файл sFilePath.
function runApp (sFilePath, sFileArgs, show, bWaitOnReturn) {
  if (bWaitOnReturn === undefined) {
    bWaitOnReturn = false
  }
  if (show === undefined) {
    show = SW_SHOW
  }
  if (sFileArgs === undefined) {
    sFileArgs = ''
  }
  var ret = 1
  log(format('[СообщениеНачалоЗапуска]',
      sFilePath,
      hidePass(sFileArgs),
      SWtoString(show),
      bWaitOnReturn))
  try {
    ret = oShell.Run(format('"{0}" {1}', sFilePath, sFileArgs), show, bWaitOnReturn)
  } catch (e) {
    log(format('[СообщениеДеталиИсключения]', e.name, e.message), true)
    return 1
  }
  log(format('[СообщениеРезультатЗапуска]', ret), ret !== 0)
  return ret
}

function hidePass (text) {
  return text
    .replace('/P"' + InfoBasePassword + '"', '/P"******"')
    .replace('/P"' + ClusterPassword + '"', '/P"******"')
    .replace('Pwd=\'' + InfoBasePassword + '\'', 'Pwd=\'******\'')
}

function clearLogFile () {
  var outFile = oFileSystemObject.OpenTextFile(outFileName, ForWriting, true, TristateTrue)
  outFile.Close()
}

// Записать текст в лог
function log (text, failed) {
  if (failed === undefined) {
    failed = false
  }
  logFile(text, failed)
}

// Записать текст в лог-файл
function logFile (text, failed) {
  var date = new Date()
  var now = ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear() + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2)
  var f
  try {
    f = oFileSystemObject.OpenTextFile(outFileName, ForAppending, true, TristateTrue)
  } catch (e) { return }
  try {
    var status = (failed === false ? '{OK}' : '{ERR}')
    f.WriteLine(format('{0} {1} {2}', now, status, text))
  } finally {
    try {
      f.Close()
    } catch (e) { }
  }
}

// Записать текст из временного лог-файла
function appendLog (logEncoding) {
  if (logEncoding == 'ASCII' || v8logEncoding == 'ASCII') { 
    return appendLogASCII()
  } else {
    return appendLogUTF8()
  }
}

function appendLogASCII () {
  var f = null
  var outf
  var text
  try {
    f = oFileSystemObject.OpenTextFile(tempLogFileName, ForReading, false, TristateFalse)
    outf = oFileSystemObject.OpenTextFile(outFileName, ForAppending, true, TristateTrue)
  } catch (e) { return }
  try {
    if (!f.AtEndOfStream) {
      text = f.ReadAll()
      outf.WriteLine('')
      outf.WriteLine(text)
      outf.WriteLine('')
    }
  } finally {
    try {
      f.Close()
      outf.Close()
    } catch (e) { return }
  }
  return (text && text.length > 0)
}

function appendLogUTF8 () {
  try {
    oADODBStream.Open()
    oADODBStream.LoadFromFile(tempLogFileName)
    text = oADODBStream.ReadText()
  } finally {
    try {
      oADODBStream.Close()
    } catch (e) { return } 
  }
  try { 
    outf = oFileSystemObject.OpenTextFile(outFileName, ForAppending, true, TristateTrue)
    outf.WriteLine('')
    outf.WriteLine(text)
    outf.WriteLine('')
    } finally {
    try {
      outf.Close()
    } catch (e) { return } 
  }
  return (text && text.length > 0)
}

// Инициализация
function initialize () {
  log(format('[СообщениеПутьКФайлуСкрипта]', thisFileName))
  log(format('[СообщениеСчетчикФайловОбновления]', cfgFileNames.length))
  for (var i = 0; i < cfgFileNames.length; i++) {
    var fileInfo = GetRequired(cfgFileNames[i], null)
    var required = fileInfo.requiredVersion ? '([СообщениеВажность])' : '';
    log(format('{0}. {1} {2}', i + 1, fileInfo.filePath, required))
  }
  return 0
}

// Финализация
function finalize (success) {
  if (success === undefined) {
    success = false
  }

  deleteScheduleTask()

  // Запись результата обновления в Event Log
  writeEventLog(success)

  if (!success) {
    if (UseRestore && backupCreated) {
      log('[СообщениеВосстановлениеБазы]')
      restoreDB()
    }
    allowConnections() // Разрешение подключений
  }

  setResult(success)

  // очистка глобального COM-соединения
  ComConnection = null
}

function deleteScheduleTask () {
  if (taskNameScheduleService !== '') {
    log(format('[СообщениеУдалениеЗадачиПланировщика]', taskNameScheduleService))
    try {
      var schedule = new ActiveXObject('Schedule.Service')
      schedule.Connect()

      var root = schedule.GetFolder('\\')
      root.DeleteTask(taskNameScheduleService, 0)
    } catch (ex) {
      log(format('[СообщениеОтказУдаленияЗадачиПланировщика]', ex.message), true)
    }
  }
}

function createConnection () {
  if (!useComConnector) {
    return null
  }
  if (ComConnection != null) {
    return ComConnection
  }
  try {
    log('[СообщениеНачалоСеансаСоединенияСБазой]', false)
    var ComConnector = new ActiveXObject(comConnectorName)
    ComConnection = ComConnector.Connect(connectionString)
    return ComConnection
  } catch (e) {
    log(format('[СообщениеОтказСоединенияСБазой]', e.name, e.message), true)
    return null
  }
}

function doSetResult (success) {
  if (useComConnector) {
    var connection = createConnection()
    if (connection == null) {
      return 1
    }
    var res = 0
    try {
      log(format('[СообщениеВызовЗавершитьОбновление]', success, emailAddress, adminName))
      connection.ОбновлениеКонфигурации.ЗавершитьОбновление(success, emailAddress, adminName)
    } catch (e) {
      log(format('[СообщениеОтказПриВызовеЗавершитьОбновление]', e.name, e.message), true)
      res = 2
    }
  }
  if (success) {
    log('[СообщениеРезультатОбновленияБазы]', false)
  } else {
    log('[СообщениеОтказОбновленияБазы]', true)
  }
  return res
}

// Передать в приложение результат выполнения
function setResult (success) {
  var result = doSetResult(success)
  CollectGarbage()
  return result
}

// Записать результат выполнения процедуры обновления в Event Log
function writeEventLog (success) {
  try {
    var eventKind = success ? EVENT_SUCCESS : EVENT_CRITICAL
    var message
    if (success) {
      message = '[СообщениеРезультатОбновленияБазы]';
    } else {
      message = '[СообщениеОтказОбновленияБазы]';
    }
    message += format(' [СообщениеПараметрыБазы]', infoBasePath)
    if (!success) {
      message += ' [СообщениеОбновлениеЛогирование1С]';
    }
    oShell.LogEvent(eventKind, message)
  } catch (e) {
    log(format('[СообщениеОтказЛогирования]', e.name, e.message), true)
  }
}

// Создание резервной копии информационной базы
function backupDB () {
  if (!createBackup) {
    return 0
  }
  var ret = 0
  log(format('[СообщениеКопированиеБазы]', BaseFileName, backupFileName))
  
  try {
    
    if (!oFileSystemObject.FileExists(BaseFileName)) {
      throw new Error(format('[СообщениеФайлБазыНеСуществует]', BaseFileName))
    }
    
    if (!oFileSystemObject.FolderExists(oFileSystemObject.GetParentFolderName(backupFileName))) {
      throw new Error(format('[СообщениеКаталогРезервнойКопииБазыНеСуществует]', backupFileName))
    }
    
    if (oFileSystemObject.FileExists(backupFileName)) {
      var ThisFile = oFileSystemObject.GetFile(backupFileName)
      throw new Error(
        format('[СообщениеПараметрыФайлаРезервнойКопии]',
          backupFileName,
          ThisFile.DateCreated,
          ThisFile.DateLastAccessed,
          ThisFile.DateLastModified,
          ThisFile.Size,
          ThisFile.Type,
          AttributesPresentation(ThisFile.Attributes)
        )
      )
    }
    
    try {
      var drive = oFileSystemObject.GetDrive(oFileSystemObject.GetDriveName(backupFileName))
    } catch (ex2) {
      throw new Error(
        format('[СообщениеДискНеСуществует]',
          backupFileName,
          ex2.name,
          ex2.message
        )
      )
    }
    
    if (!drive.IsReady) {
      throw new Error(format('[СообщениеДискНедоступен]', backupFileName))
    }
    
    var waitBaseFile = true
    while (waitBaseFile) {
      try {
        var oFile = oFileSystemObject.OpenTextFile(BaseFileName, ForAppending, true, TristateFalse)
      } catch (ex) {
        if (oHTA != null) {
          return -1
        } else {
          WScript.Echo(ex.message) 
          WScript.Sleep(18 * 1000) // Ждем и повторяем проверку, освободился ли файл ИБ.
        }
        continue;
      }
      oFile.Close()
      waitBaseFile = false
    }

    var fileDB = oFileSystemObject.GetFile(BaseFileName)
    var requiredFreeSize = fileDB.size * 2
    if (drive.FreeSpace < requiredFreeSize) {
      throw new Error(
       format('[СообщениеДисковогоПространстваНедостаточно]',
          requiredFreeSize / 1024 / 1024,
          drive.DriveLetter,
          drive.FreeSpace / 1024 / 1024,
          fileDB.size / 1024 / 1024,
          DriveTypeName(drive.DriveType)
        )
      )
    } else {
      log(format('[СообщениеДисковогоПространстваДостаточно]',
          drive.DriveLetter,
          drive.FreeSpace / 1024 / 1024,
          fileDB.size / 1024 / 1024,
          DriveTypeName(drive.DriveType)
        ), 
        false)
    }
    
    oFileSystemObject.CopyFile(BaseFileName, backupFileName, true)
    log('[СообщениеРезультатСозданияРезервнойКопииБазы]', false)
    
  } catch (e) {
    CollectGarbage()
    log(
      format(
        '[СообщениеОтказСозданияРезервнойКопииБазыПодробно]',
        e.name,
        e.message
      ),
      true
    )
    ret = 1
  }
  if (ret === 0) {
    backupCreated = true
  }
  return ret
}

function DriveTypeName (DriveType) {
  switch (DriveType) {
    case 0:
      return 'Unknown'
    case 1:
      return 'Removable'
    case 2:
      return 'Fixed'
    case 3:
      return 'Network'
    case 4:
      return 'CD-ROM'
    case 5:
      return 'RAM Disk'
    default:
      return 'Undefined'
  }
}

function AttributesPresentation (value) {
  var log = ''
  if (value & 1) {
    log += 'Readonly\n'
  }
  if (value & 2) {
    log += 'Hidden\n'
  }
  if (value & 4) {
    log += 'System\n'
  }
  if (value & 16) {
    log += 'Directory\n'
  }
  if (value & 32) {
    log += 'Archive\n'
  }
  if (value & 128) {
    log += 'Normal\n'
  }
  if (value & 256) {
    log += 'Temporary\n'
  }
  if (value & 1024) {
    log += 'Alias\n'
  }
  if (value & 2048) {
    log += 'Compressed\n'
  }
  return log
}

// Восстановление информационной базы из резервной копии
function restoreDB () {
  if (!backupCreated) {
    return 0
  }
  var ret = 0
  try {
    oFileSystemObject.CopyFile(backupFileName, BaseFileName, true)
    log(format('[СообщениеРезультатВосстановленияБазы]', ret), ret !== 0)
  } catch (e) {
    log(format('[СообщениеОтказВосстановленияБазыПодробно]', e.name, e.message), true)
    ret = -1
  }
  return ret
}

function doAllowConnections () {
  if (connectionsDenied) {
    var connection = createConnection()
    if (connection == null) {
      return (useComConnector ? 1 : 0)
    }
    try {
      log('[СообщениеВызовРазрешитьРаботуПользователей]')
      connection.СоединенияИБ.РазрешитьРаботуПользователей()
      connectionsDenied = false
      connection = null
      CollectGarbage()
    } catch (e) {
      connection = null
      CollectGarbage()
      log(format('[СообщениеОтказВызоваРазрешитьРаботуПользователей]', e.name, e.message), true)
      return 3
    }
  }
  return 0
}

// Разрешение подключений новых соединений
function allowConnections () {
  var result = doAllowConnections()
  ComConnection = null
  CollectGarbage()
  return result
}

function doExecuteUpdate (lastVersion) {
  if (useComConnector && lastVersion) {
    try {
      if (addDeletePatches() != 0) {
        throw new Error('[СообщениеОтказОбновленияИсправлений]')
      }
    } catch (e) {
      log(format('[СообщениеОтказВызоваОбновитьИсправленияИзСкрипта]', e.name, e.message), true)
      return 2
    }
  }
  if (useComConnector && doBlockUsers) {
    var connection = createConnection()
    if (connection == null) {
      return 1
    }
    try {
      log(format('[СообщениеВызовВыполнитьОбновлениеИнформационнойБазы]', !lastVersion))
      connection.ОбновлениеИнформационнойБазыВызовСервера.ВыполнитьОбновлениеИнформационнойБазы(!lastVersion)
      connection = null
      CollectGarbage()
    } catch (e) {
      connection = null
      CollectGarbage()
      log(format('[СообщениеОтказВызоваВыполнитьОбновлениеИнформационнойБазы]', e.name, e.message), true)
      return 2
    }
    return 0
  } else {
    var result = runApp(
      v8client,
      format(
        'ENTERPRISE {0} {1} /AllowExecuteScheduledJobs -Off /C"ВыполнитьОбновлениеИЗавершитьРаботу;РегламентныеЗаданияОтключены"',
        infoBasePath,
        infoBaseAuthorization),
      SW_SHOW,
      true)
    if (result === 0 && oFileSystemObject.FileExists(errorFileName)) {
      log('[СообщениеОтказОбновленияБазыОбщее]', true)
      appendLog('ASCII')
      result = 1
    }
    return result
  }
}

// Выполнение обработчиков обновления информационной базы через com
function executeUpdate (lastVersion) {
  var result = doExecuteUpdate(lastVersion)
  ComConnection = null
  CollectGarbage()
  return result
}

function doDisconnectAndBlockUsersHTA (connection) {
  if (connection == null) {
    return 1
  }
  var result = 0
  try {
    while (true) {
      switch (disconnectionStep) {
        case 0:
        {
          log('СоединенияИБ.УстановитьБлокировкуСоединений()')
          connection.СоединенияИБ.УстановитьБлокировкуСоединений('[СообщениеБлокировкаБазы]', unlockCode)
          disconnectionInterval = connection.СоединенияИБ.ПараметрыБлокировкиСеансов().ИнтервалОжиданияЗавершенияРаботыПользователей * 1000
          disconnectionStartDateTime = connection.СоединенияИБ.ПараметрыБлокировкиСеансов().Начало
          if (connection.ЗначениеЗаполнено(disconnectionStartDateTime)) {
            disconnectionStep++
          } else {
            disconnectionStep += 2
          }
          break
        }
        case 1:
        {
          if (!connection.СоединенияИБ.УстановленаБлокировкаСоединений() ||
            connection.СоединенияИБ.КоличествоСеансовИнформационнойБазы(false) <= 1) {
            disconnectionStep++
            break
          }
          var now = new Date()
          // если интервал ожидания еще не истек, то ждем еще раз
          if (now - disconnectionInterval <= disconnectionStartDateTime) {
            return -1
          }
          disconnectionStep++
          break
        }
        case 2:
        {
          if (!connection.СоединенияИБ.УстановленаБлокировкаСоединений()) {
            log('[СообщениеОтказЗавершенияРаботыПользователей]', true)
            return 3
          }

          if (connection.СоединенияИБ.КоличествоСеансовИнформационнойБазы(false) <= 1) {
            return 0
          }
          // после начала блокировки сеансы всех пользователей должны быть отключены
          // если этого не произошло пробуем принудительно прервать соединение.
          doDisconnectConnections(connection)
          if (connection.СоединенияИБ.КоличествоСеансовИнформационнойБазы(false) > 1) {
            connection.СоединенияИБ.РазрешитьРаботуПользователей()

            var message = connection.СоединенияИБ.СообщениеОНеотключенныхСеансах()
            log(message, true)
            return 3
          }
          return 0
        }
      }
    }
  } catch (e) {
    CollectGarbage()
    log(format('[СообщениеОтменаБлокировкиРаботыПользователей]', e.name, e.message), true)
    result = 2
  }
  return result
}

// Завершение работы пользователей и запрет на подключение новых соединений
// Возвращает:
//   -1           - выполнение отложено, необходимо повторить вызов функции через 18 секунд
//   0            - функция выполнена успешно
//   другое число - код ошибки
//
function disconnectAndBlockUsersHTA () {
  if (!doBlockUsers) {
    connectionsDenied = true
    return 0
  }
  var connection = createConnection()
  if (connection == null && useComConnector) {
    return 1
  }
  var result = -1
  if (useComConnector) {
    try {
      result = doDisconnectAndBlockUsersHTA(connection)
    } finally {
      if (result !== -1) {
        connection = null
        ComConnection = null
        CollectGarbage()
        log('[СообщениеКонецСеансаСоединенияСБазой]', false)
      }
    }
  } else {
    result = 0
  }
  if (result === 0) {
    connectionsDenied = true
  }
  return result
}

function doDisconnectAndBlockUsers () {
  var connection = createConnection()
  if (connection == null) {
    return (useComConnector ? 1 : 0)
  }
  try {
    log('[СообщениеБлокировкаРаботыПользователейЛогирование]')
    connection.СоединенияИБ.УстановитьБлокировкуСоединений('[СообщениеБлокировкаРаботыПользователей]', unlockCode)

    var interval = connection.СоединенияИБ.ПараметрыБлокировкиСеансов().ИнтервалОжиданияЗавершенияРаботыПользователей * 1000

    var startDateTime = connection.ПолучитьБлокировкуСеансов().Начало
    var now = new Date()

    if (connection.ЗначениеЗаполнено(startDateTime)) {
      while (now - interval <= startDateTime) {
        if (!connection.ПолучитьБлокировкуСеансов().Установлена) {
          break
        }
        connectionsNum = connection.СоединенияИБ.КоличествоСеансовИнформационнойБазы(false)
        log(format('[СообщениеСчетчикСеансовБазы]', connectionsNum))
        if (connectionsNum <= 1) {
          break
        }
        WScript.Sleep(18 * 1000) // Ждем 18 секунд до следующей проверки.
        now = new Date()
      }
    }

    var locked = connection.ПолучитьБлокировкуСеансов().Установлена
    log(format('[СообщениеРезультатБлокировкиСеансов]', locked))
    if (!connection.ПолучитьБлокировкуСеансов().Установлена) {
      log('[СообщениеОтказЗавершенияРаботыПользователей]', true)
      return 3
    }

    // после начала блокировки сеансы всех пользователей должны быть отключены
    // если этого не произошло, пробуем принудительно прервать соединения.
    doDisconnectConnections(connection)
    connectionsNum = connection.СоединенияИБ.КоличествоСеансовИнформационнойБазы(false);
    log(format('[СообщениеСчетчикСеансовБазы]', connectionsNum))
    if (connectionsNum > 1) {
      connection.СоединенияИБ.РазрешитьРаботуПользователей()
      var message = connection.СоединенияИБ.СообщениеОНеотключенныхСеансах()
      log(message, true)
      return 3
    }
  } catch (e) {
    CollectGarbage()
    log(
      format(
        '[СообщениеОтменаБлокировкиРаботыПользователей]',
        e.name,
        e.message),
      true)
    return 2
  }
  return 0
}

function doDisconnectConnections (connection) {
  var adminParams = connection.СтандартныеПодсистемыСервер.ПараметрыАдминистрирования()
  adminParams.ПарольАдминистратораИнформационнойБазы = InfoBasePassword
  adminParams.ПарольАдминистратораКластера = ClusterPassword

  connection.СоединенияИБКлиентСервер.УдалитьВсеСеансыКромеТекущего(adminParams)

  WScript.Sleep(15 * 1000) // Ждем 15 секунд на случай зависших сеансов.
  
  retry = 3;
  while (retry > 0) {
    connectionsNum = connection.СоединенияИБ.КоличествоСеансовИнформационнойБазы(false);
    if (connectionsNum <= 1) {
      break
    }
    log(format('[СообщениеСчетчикЗависшихСеансовБазы]', connectionsNum, retry))
    WScript.Sleep(15 * 1000) // Ждем 15 секунд до следующей проверки.
    retry = retry - 1
  }
}

// Завершение работы пользователей и запрет на подключение новых соединений
function disconnectAndBlockUsers () {
  var result = 0
  if (doBlockUsers) {
    result = doDisconnectAndBlockUsers()
  }

  ComConnection = null
  CollectGarbage()
  WScript.Sleep(1000) // ждем 1 секунду (достаточно для завершения COM-соединения).

  if (result === 0 && doBlockUsers) {
    connectionsDenied = true
  }
  return result
}

// Загрузка файла обновления в основную базу
function loadCfg (fileName) {
  // /LoadCfg<имя cf файла> (для базовых версий не используется) загрузка конфигурации из файла
  var ret = runApp(
    v8conf,
    format(
      'CONFIG {0} {1} /LoadCfg "{2}" /Out "{3}" /UC{4} /DisableStartupMessages /DisableStartupDialogs',
      infoBasePath,
      infoBaseAuthorization,
      fileName,
      tempLogFileName,
      unlockCode),
    SW_SHOW,
    true)
  appendLog()
  return ret
}

// Загрузка файла обновления в основную базу
function updateCfg (fileName) {
  // /UpdateCfg<имя cf | cfu файла> обновление конфигурации, находящейся на поддержке
  var ret = runApp(
    v8conf,
    format(
      'CONFIG {0} {1} /UpdateCfg "{2}" /Out "{3}" /UC{4} /DisableStartupMessages /DisableStartupDialogs',
      infoBasePath,
      infoBaseAuthorization,
      fileName,
      tempLogFileName,
      unlockCode),
    SW_SHOW,
    true)
  appendLog()
  return ret
}

// Обновление конфигурации информационной базы
function updateDbCfg () {
  // /UpdateDBCfg - обновление конфигурации базы данных
  var ret = runApp(
    v8conf,
    format(
      'CONFIG {0} {1} /UpdateDBCfg -server /Out "{2}" /UC{3} /DisableStartupMessages /DisableStartupDialogs',
      infoBasePath,
      infoBaseAuthorization,
      tempLogFileName,
      unlockCode),
    SW_SHOW,
    true)
  appendLog()
  return ret
}

// Выполнение тестирования и исправления
function compressDB () {
  if (!makeCompression) {
    return 0
  }

  var ret = runApp(
    v8conf, 
    format(
      'CONFIG {0} {1} /IBCheckAndRepair -IBCompression /Out "{2}" /UC{3} /DisableStartupMessages /DisableStartupDialogs',
      infoBasePath,
      infoBaseAuthorization,
      tempLogFileName,
      unlockCode),
    SW_SHOW,
    true)
  appendLog()
  return ret
}

function doDeferredHandlers () {
  if (!executeDeferredHandlers) {
    return 0
  }

  var connection = createConnection()
  if (connection == null) {
    return (useComConnector ? 1 : 0) // в базовых версиях отложенные обработчики выполняются из основного сеанса перед обновлением
  }

  try {
    log('[СообщениеВызовВыполнитьОтложенноеОбновлениеСейчас]')
    connection.ОбновлениеИнформационнойБазыСлужебный.ВыполнитьОтложенноеОбновлениеСейчас()
    connection = null
    CollectGarbage()
  } catch (e) {
    connection = null
    CollectGarbage()
    log(
      format(
        '[СообщениеОтказВызоваВыполнитьОтложенноеОбновлениеСейчас]',
        e.name,
        e.message),
      true)
    return 2
  }
  return 0
}

// Выполнение отложенных обработчиков обновления информационной базы через com
function runDeferredHandlers () {
  var result = doDeferredHandlers()
  connection = null
  ComConnection = null
  CollectGarbage()
  return result
}

// Получение имени файла обновления и определение является ли он приоритетным (обязателен запуск)
function GetRequired (filePath) {
  var fileProperties = Object()
  fileProperties.filePath = filePath
  fileProperties.requiredVersion = filePath.substr(0, 1) === '+'
  if (fileProperties.requiredVersion) {
    fileProperties.filePath = filePath.substr(1)
  }
  return fileProperties
}

function fromUnicode (text) {
  var str = '';
  if (typeof text !== 'string') {
    return str
  }
  for (var i = 0; i < text.length / 4; i++) {
    str = str + String.fromCharCode(text.slice(4 * i, 4 * i + 4))
  }
  str = str.replace(/"/g, '""')
  return str
}

// Интерактивный запуск "1С:Предприятие"
function runEnterprise () {
  if (startEnterprise) {
    return runApp(
      v8client,
      format(
        'ENTERPRISE {0} {1} {2}',
        infoBasePath,
        infoBaseAuthorization,
        runAppAdditionalParams),
      SW_SHOW,
      false)
  }
  return 0
}

function addDeletePatches() {
  var fixFileNamesString = fixFileNames.join('\n')
  var removeFixNamesString = removeFixNames.join('\n')

  registerCOM()
  
  var result = runApp('wscript.exe',
    format('"{0}\\add-delete-patches.js" /ConnectionString:"{1}" /COMConnectorName:"{2}" /FixFileNames:"{3}" /RemoveFixNames:"{4}" /Out:"{5}\\{6}"',
      thisFileDir,
      connectionString.replace(/"/g, '\''),
      comConnectorName,
      fixFileNamesString,
      removeFixNamesString,
      thisFileDir,
      tempLogFileName
    ),
    SW_HIDE, true)
  appendLog('ASCII')
  return result
}

function DeletePatches() {
 
 if (!useComConnector) {
    return 0
  }
 
 var Action = 'RemoveAll'
 
 registerCOM()
 
 try {
   var result = runApp('wscript.exe',
      format('"{0}\\add-delete-patches.js" /ConnectionString:"{1}" /COMConnectorName:"{2}" /Action:"{3}" /Out:"{4}\\{5}"',
        thisFileDir,
        connectionString.replace(/"/g, '\''),
        comConnectorName,
        Action,
        thisFileDir,
        tempLogFileName
      ),
      SW_HIDE, true)
    appendLog('ASCII')

  } catch (e) {
    log(format('[СообщениеОтказВызоваУдалитьИсправленияИзСкрипта]', e.name, e.message), true)
    result = 2;
  }
  
  if (result != 0) {
    log('[СообщениеОтказУдаленияИсправлений]')
  }
  
  return result
}

function registerCOM() {
  isSchedule = (taskNameScheduleService !== '')
  param = isSchedule ? format('/s "{0}"', v8comcntr) : format('/n /i:user /s "{0}"', v8comcntr)
  return runApp('regsvr32.exe', param, SW_HIDE, true)
}

function executeLoadExt () {
  var result = doExecuteLoadExt()
  ComConnection = null
  CollectGarbage()
  return result
}

function doExecuteLoadExt() {

  var result = runApp(
    v8client,
    format(
      'ENTERPRISE {0} {1} /AllowExecuteScheduledJobs -Off /DisableStartupMessages /DisableStartupDialogs /C"ВыполнитьЗагрузкуРасширенийИЗавершитьРаботу;РегламентныеЗаданияОтключены;РазрешитьРаботуПользователей" /UC {2}',
      infoBasePath,
      infoBaseAuthorization,
      unlockCode),
    SW_SHOW,
    true)
  
  if (result === 0 && oFileSystemObject.FileExists(errorFileName)) {
    log('[СообщениеОтказОбновленияБазыОбщее]', true)
    appendLog('ASCII')
    result = 1
  }  
  
  return result
}


function ClearTempFiles () {
  var tempFiles = ['main.js', 'helpers.js', 'add-delete-patches.js', 'templog.txt', // общие файлы
    'addsheduletask.js', 'updater.js',                         // неинтерактивный запуск
    'splash.png', 'splash.ico', 'progress.gif', 'splash.hta']; // интерактивный запуск
  
  for (var i = 0; i < tempFiles.length; i++) {
    try {
      if (oFileSystemObject.FileExists(thisFileDir + '\\' + tempFiles[i])) {
        oFileSystemObject.DeleteFile(thisFileDir + '\\' + tempFiles[i])
      }
    } catch (e) { }
  }
}

if (oHTA != null) {
  thisFileName = eval('oHTA.commandLine')
  thisFileDir = thisFileName.substr(1, thisFileName.lastIndexOf('\\') - 1)
  InfoBasePassword = thisFileName.substr(thisFileName.indexOf('[p1]') + 4, thisFileName.indexOf('[/p1]') - thisFileName.indexOf('[p1]') - 4)
  ClusterPassword = thisFileName.substr(thisFileName.indexOf('[p2]') + 4, thisFileName.indexOf('[/p2]') - thisFileName.indexOf('[p2]') - 4)
  thisFileName = thisFileName.substr(1, thisFileName.indexOf('[p1]') - 4)
} else {
  thisFileName = eval('WScript.ScriptFullName')
  thisFileDir = thisFileName.substr(0, thisFileName.lastIndexOf('\\') + 1)
  InfoBasePassword = eval('WScript.Arguments').Named.Item('p1')
  ClusterPassword = eval('WScript.Arguments').Named.Item('p2')
}

var oShell = new ActiveXObject('WScript.Shell')
oShell.CurrentDirectory = thisFileDir

var oFileSystemObject = new ActiveXObject('Scripting.FileSystemObject')
var oADODBStream = new ActiveXObject('ADODB.Stream')
oADODBStream.CharSet = 'utf-8'

clearLogFile()
appendLog('ASCII')

log(format('[СообщениеПараметрыCOMСоединителя]', useComConnector))

if (useComConnector) {
  registerCOM()
  var comConnectorCached = new ActiveXObject(comConnectorName) // для защиты от перерегистрации comConnector из других сеансов
}

adminName = adminName.replace(/"/g, '""')
InfoBasePassword = fromUnicode(InfoBasePassword)
ClusterPassword = fromUnicode(ClusterPassword)
var infoBaseAuthorization = format('/N"{0}" /P"{1}" /WA-', adminName, InfoBasePassword)
connectionString = format(connectionString, adminName, InfoBasePassword)

#КонецОбласти